package com.heima.wemedia.threadpoolconfig;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

@EnableAsync // 启用异步支持
@Slf4j
@Configuration
public class ThreadPoolConfig {

    // 线程池参数可从配置文件读取（示例）
    private static final int CORE_POOL_SIZE = 5;
    private static final int MAX_POOL_SIZE = 20;
    private static final int QUEUE_CAPACITY = 1000;
    private static final long KEEP_ALIVE_TIME = 60; // 单位：秒

    /**
     * 文章审核线程池（企业级规范实现）
     */
    @Bean("articleReviewExecutor")
    public ThreadPoolTaskExecutor articleReviewExecutor() {
        log.info("初始化文章审核线程池 articleReviewExecutor...");

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(CORE_POOL_SIZE);
        executor.setMaxPoolSize(MAX_POOL_SIZE);
        executor.setQueueCapacity(QUEUE_CAPACITY);
        executor.setKeepAliveSeconds((int) KEEP_ALIVE_TIME);
        executor.setThreadNamePrefix("article-review-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        // 设置自定义线程工厂
        executor.setThreadFactory(new ThreadFactory() {
            private final AtomicInteger threadNumber = new AtomicInteger(1);
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setName("article-review-thread-" + threadNumber.getAndIncrement());
                thread.setDaemon(true);
                return thread;
            }
        });

        executor.initialize(); // 必须调用初始化方法

        // 启动线程池监控（每1分钟输出一次状态）
        startThreadPoolMonitor(executor);

        return executor;
    }

    /**
     * 线程池监控方法
     */
    private void startThreadPoolMonitor(ThreadPoolTaskExecutor executor) {
        ScheduledExecutorService monitor = Executors.newSingleThreadScheduledExecutor(
                r -> new Thread(r, "thread-pool-monitor")
        );
        monitor.scheduleAtFixedRate(() -> {
            try {
                // 获取底层的ThreadPoolExecutor进行监控
                ThreadPoolExecutor threadPoolExecutor = executor.getThreadPoolExecutor();
                log.info("【线程池监控】名称=articleReviewExecutor, " +
                                "活跃线程数={}, 队列大小={}, 完成任务数={}, 总任务数={}, 最大线程数={}",
                        threadPoolExecutor.getActiveCount(),
                        threadPoolExecutor.getQueue().size(),
                        threadPoolExecutor.getCompletedTaskCount(),
                        threadPoolExecutor.getTaskCount(),
                        threadPoolExecutor.getLargestPoolSize()
                );
            } catch (Exception e) {
                log.error("线程池监控异常", e);
            }
        }, 1, 30, TimeUnit.MINUTES);
    }

    /**
     * 应用关闭时优雅关闭线程池
     */
    @Bean
    public ThreadPoolShutdownHook threadPoolShutdownHook(ThreadPoolTaskExecutor articleReviewExecutor) {
        return new ThreadPoolShutdownHook(articleReviewExecutor);
    }

    /**
     * 线程池优雅关闭钩子
     */
    static class ThreadPoolShutdownHook {
        private final ThreadPoolTaskExecutor executor;

        public ThreadPoolShutdownHook(ThreadPoolTaskExecutor executor) {
            this.executor = executor;
        }

        @SuppressWarnings("unused") // 由Spring容器调用
        public void shutdown() {
            log.info("开始关闭线程池 articleReviewExecutor...");
            executor.shutdown(); // 尝试优雅关闭
            try {
                if (!executor.getThreadPoolExecutor().awaitTermination(30, TimeUnit.SECONDS)) {
                    executor.getThreadPoolExecutor().shutdownNow(); // 强制关闭
                    log.warn("线程池强制关闭，可能存在未完成任务");
                }
                log.info("线程池 articleReviewExecutor 已关闭");
            } catch (InterruptedException e) {
                executor.getThreadPoolExecutor().shutdownNow();
                Thread.currentThread().interrupt();
                log.error("线程池关闭被中断", e);
            }
        }
    }
}